package com.webex.ta.hydra.gui.macro;

import com.webex.ta.hydra.core.Command;
import com.webex.ta.hydra.core.ParamDescriptor;
import com.webex.ta.hydra.core.macro.MacroDefinition;
import com.webex.ta.hydra.gui.table.HydraTable;
import com.webex.ta.hydra.gui.util.RolloverButton;
import com.webex.ta.hydra.util.HydraUtils;

import javax.swing.*;
import javax.swing.border.EmptyBorder;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.util.Vector;


/**
 * Created by Cisco WebEx.
 * User: vegaz
 * Date: 2010-9-13
 * Time: 15:38:36
 */
public class MacroEditor extends JDialog implements ActionListener, DocumentListener, MouseListener, ListSelectionListener {
    private static final String DEFAULT_TITLE = "Hydra Macro Editor";

    private HydraTable macroDetail;

    private JTextField macroName = new JTextField(30);

    private MacroFieldTable macroFields = new MacroFieldTable();

    private JList macros;

    private MacroListModel listModel;

    private JButton addParam = createSmallActionButton("include.png");
    private JButton removeParam = createSmallActionButton("exclude.png");
    private JButton moveUpParam = createSmallActionButton("moveup.gif");
    private JButton moveDownParam = createSmallActionButton("movedown.gif");

    private JButton addKeyword = createSmallActionButton("include.png");
    private JButton removeKeyword = createSmallActionButton("exclude.png");
    private JButton moveUpKeyword = createSmallActionButton("moveup.gif");
    private JButton moveDownKeyword = createSmallActionButton("movedown.gif");


    private JButton addMacro = createSmallActionButton("include.png");
    private JButton removeMacro = createSmallActionButton("exclude.png");
    private JButton moveUpMacro = createSmallActionButton("moveup.gif");
    private JButton moveDownMacro = createSmallActionButton("movedown.gif");

    private MacroEditorMenuBar menu = new MacroEditorMenuBar();

    private MacroDefinition current = null;

    public MacroEditor(Frame owner, boolean modal) {
        super(owner, modal);
        init();
    }

    public MacroListModel getListModel() {
        return listModel;
    }

    private JButton createSmallActionButton(String icon) {
        JButton button = new RolloverButton(HydraUtils.getImage(icon));
        button.setBorderPainted(false);
        resizeSmallButton(button);
        button.addActionListener(this);
        return button;
    }

    private void init() {
        this.setJMenuBar(menu);

        macroName.getDocument().addDocumentListener(this);

        listModel = new MacroListModel();
        macros = new JList(listModel);
        macros.setCellRenderer(new MacroListCellRenderer());
        macros.getSelectionModel().addListSelectionListener(this);
        macros.addMouseListener(this);
        macroDetail = new HydraTable();

        JSplitPane split = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT);
        split.setLeftComponent(createLeftPanel());
        split.setRightComponent(createMainPanel());
        split.setResizeWeight(0.2);

        this.add(split);
        this.pack();
    }

    private void resizeSmallButton(JButton button) {
        button.setPreferredSize(new Dimension(18, 18));
        button.setMaximumSize(new Dimension(18, 18));
    }

    private Component createLeftPanel() {
        JPanel p = new JPanel(new BorderLayout());

        Box box = Box.createHorizontalBox();
        box.setBorder(new EmptyBorder(5, 5, 5, 5));
        box.add(new JLabel("Macros"));
        box.add(Box.createGlue());
        box.add(moveDownMacro);
        box.add(moveUpMacro);
        box.add(removeMacro);
        box.add(addMacro);
        p.add(box, BorderLayout.NORTH);

        JScrollPane scrollPane = new JScrollPane();
        scrollPane.setViewportView(macros);
        scrollPane.setPreferredSize(new Dimension(150, 200));
        p.add(scrollPane);

        return p;
    }

    private Component createMainPanel() {
        JPanel p = new JPanel(new BorderLayout());
        p.add(createNamePanel(), BorderLayout.NORTH);

        Box box = Box.createVerticalBox();
        box.setBorder(new EmptyBorder(5, 5, 5, 5));
        box.add(createParamTable());
        box.add(createContentTable());
        p.add(box, BorderLayout.CENTER);
        return p;
    }

    private Component createNamePanel() {
        JPanel p = new JPanel(new BorderLayout());
        p.setBorder(new EmptyBorder(5, 5, 5, 5));
        p.add(new JLabel("Macro Name"), BorderLayout.WEST);
        p.add(macroName, BorderLayout.CENTER);
        return p;
    }

    private Component createParamTable() {
        JPanel p = new JPanel(new BorderLayout());
        p.setBorder(new EmptyBorder(5, 5, 5, 5));

        Box box = Box.createHorizontalBox();
        box.add(new JLabel("Parameters"));
        box.add(Box.createGlue());

        box.add(moveDownParam);
        box.add(moveUpParam);
        box.add(removeParam);
        box.add(addParam);
        p.add(box, BorderLayout.NORTH);

        JScrollPane scrollPane = new JScrollPane();
        scrollPane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
        scrollPane.setViewportView(macroFields);
        scrollPane.setPreferredSize(new Dimension(600, 80));
        p.add(scrollPane, BorderLayout.CENTER);

        return p;
    }

    private Component createContentTable() {
        JPanel p = new JPanel(new BorderLayout());
        p.setBorder(new EmptyBorder(5, 5, 5, 5));

        Box box = Box.createHorizontalBox();
        box.add(new JLabel("Contents"));
        box.add(Box.createGlue());
        box.add(addKeyword);
        p.add(box, BorderLayout.NORTH);


        JScrollPane scrollPane = new JScrollPane();
        scrollPane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
        scrollPane.setViewportView(macroDetail);
        scrollPane.setPreferredSize(new Dimension(600, 300));
        p.add(scrollPane, BorderLayout.CENTER);
        return p;
    }

    public HydraTable getTable() {
        return macroDetail;
    }

    public void reset() {
        listModel.clear();
        macros.repaint();
        macroName.setText("");
        macroFields.getModel().reset();
        macroDetail.getModel().reset();
    }

    public void macroFileLoaded(String file) {
        menu.macroFileLoaded(file);
    }


    public void setExtendedFrameTitle(String fname) {
        // file New operation may set to null, so just return app name
        if (fname == null) {
            setTitle(DEFAULT_TITLE);
            return;
        }

        // allow for windows / chars in filename
        String temp = fname.replace('\\', '/');
        String simpleName = temp.substring(temp.lastIndexOf("/") + 1);
        setTitle(simpleName + " (" + fname + ") - " + DEFAULT_TITLE);
    }

    public void actionPerformed(ActionEvent e) {
        if (e.getSource() == addMacro) {
            listModel.addElement(new MacroDefinition());
            macros.setSelectedIndex(listModel.getSize() - 1);
        } else if (e.getSource() == removeMacro) {
            for (Object def : macros.getSelectedValues()) {
                listModel.removeElement(def);
            }
            this.loadDefinition(null);
        } else if (e.getSource() == moveUpMacro) {
            moveMacro(-1);
        } else if (e.getSource() == moveDownMacro) {
            moveMacro(1);
        }


        if (current != null) {
            if (e.getSource() == addParam) {
                current.addField(new ParamDescriptor(""));
                macroFields.getModel().fireTableDataChanged();
            } else if (e.getSource() == removeParam) {
                for (int i = macroFields.getSelectedRows().length - 1; i >= 0; i--) {
                    macroFields.getModel().removeElementAt(macroFields.getSelectedRows()[i]);
                }
                macroFields.getModel().fireTableDataChanged();
            } else if (e.getSource() == moveUpParam) {
                moveParam(-1);
            } else if (e.getSource() == moveDownParam) {
                moveParam(1);
            } else if (e.getSource() == addKeyword) {
                current.addStep(new Command());
                macroDetail.getModel().fireTableDataChanged();
            }
        }
    }

    private void moveMacro(int direction) {
        int row = macros.getSelectedIndex();
        if (row >= 0) {
            stopEdit();
            if (listModel.move(row, direction)) {
                macros.setSelectedIndex(row + direction);
            }
        }
    }

    private void moveParam(int direction) {
        int row = macroFields.getSelectedRow();
        if (row >= 0) {
            stopEdit();
            if (macroFields.getModel().move(row, direction)) {
                macroFields.repaint();
                macroFields.getSelectionModel().setSelectionInterval(row + direction, row + direction);
            }
        }
    }

    private void stopEdit() {
        macroFields.stopEdit();
        macroDetail.stopEdit();
    }


    private void loadDefinition(MacroDefinition def) {
        if (def != null) {
            macroName.setText(def.getName());
            macroFields.getModel().setFields(def.getFields());
            macroDetail.getModel().setRoot(def.getRoot());
        } else {
            macroName.setText("");
            macroFields.getModel().reset();
            macroDetail.getModel().reset();
        }
    }

    public Vector<MacroDefinition> getMacroDefinitions() {
        return ((MacroListModel) macros.getModel()).getDefinitions();
    }

    public void insertUpdate(DocumentEvent e) {
        macroNameChanged();
    }

    public void removeUpdate(DocumentEvent e) {
        macroNameChanged();
    }

    public void changedUpdate(DocumentEvent e) {
        macroNameChanged();
    }

    private void macroNameChanged() {
        if (current != null) {
            current.setName(macroName.getText());
        }
        macros.repaint();
    }

    public void mouseClicked(MouseEvent e) {
        int selected = macros.getSelectedIndex();
        if (selected >= 0 && selected < listModel.getSize()) {
            MacroDefinition def = listModel.get(selected);
            if (def == current)
                return;
            current = def;
            loadDefinition(current);
        }
    }

    public void valueChanged(ListSelectionEvent e) {
        MacroDefinition newSelection = (MacroDefinition) macros.getSelectedValue();
        if (current != newSelection) {
            current = newSelection;
            loadDefinition(current);
        }
    }

    public void mousePressed(MouseEvent e) {
    }

    public void mouseReleased(MouseEvent e) {
    }

    public void mouseEntered(MouseEvent e) {
    }

    public void mouseExited(MouseEvent e) {
    }


}
